#include "stdafx.h"
#include "EXDropdownComboBox.h"

IMPLEMENT_DYNAMIC(CEXDropdownComboBox, CComboBox)

CEXDropdownComboBox::CEXDropdownComboBox()
{
	m_nComboTopHeight = 0;
	m_nComboBottomHeight = 0;
	m_nComboLeftWidth = 0;
	m_nComboRightWidth = 0;
	m_nComboBkgndID = 0;
	m_nComboNumOfBgPics = 0;
	m_crComboBkgnd = RGB(255, 0, 255);
	m_crListNormal = RGB(206,209,226);
	m_crListFocus = RGB(49, 106, 197);
	m_bSetComboBg = FALSE;
	m_bSelect = FALSE;
	m_pChildEdit = NULL;
}

CEXDropdownComboBox::~CEXDropdownComboBox()
{
}


BEGIN_MESSAGE_MAP(CEXDropdownComboBox, CComboBox)
	ON_WM_SIZE()
	ON_CONTROL_REFLECT(CBN_CLOSEUP, &CEXDropdownComboBox::OnCbnCloseup)
	ON_CONTROL_REFLECT(CBN_DROPDOWN, &CEXDropdownComboBox::OnCbnDropdown)
	ON_WM_ERASEBKGND()
	ON_WM_NCPAINT()
	ON_WM_PAINT()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_MESSAGE(WM_DEF_ENCHANGE, &CEXDropdownComboBox::OnDefEnchange)
	ON_WM_WINDOWPOSCHANGING()
	ON_WM_WINDOWPOSCHANGED()
END_MESSAGE_MAP()

BOOL CEXDropdownComboBox::CursorInWindow()
{
	POINT ptCur;
	if (GetCursorPos(&ptCur))
	{
		ScreenToClient(&ptCur);

		CRect rcWnd;
		GetWindowRect(rcWnd);
		ScreenToClient(rcWnd);

		if (rcWnd.PtInRect(ptCur))
			return TRUE;
	}
	return FALSE;
}

void CEXDropdownComboBox::SetResSet(CEXBaseResSet* pResSet)
{
  m_pComboResSet = (CEXDropdownComboBoxResSet *)pResSet;
 
  SetFont(m_pComboResSet->m_font);
  SetListColor(m_pComboResSet->m_crNormal, m_pComboResSet->m_crFocus);

  if(m_pComboResSet->m_nType == DROPDOWN_COMBO_CTRL)
    SetComboBgBitmaps(m_pComboResSet->m_arrImgId.GetAt(0), 
                      m_pComboResSet->m_arrImgId.GetAt(1), 
                      m_pComboResSet->m_nImg_DivideCnt, 
                      m_crComboBkgnd,4,4,4,20);
  
  m_edText.SetResSet(m_pComboResSet->m_pEditResSet);
}

void CEXDropdownComboBox::DrawFrame(CDC * pDC)
{
	if (!m_bSetComboBg)
		return;

	BOOL bAlloc = FALSE;
	if (!pDC)
	{
		bAlloc = TRUE;
		pDC = GetDC();
	}

	CRect rcClient;
	GetWindowRect(rcClient);
	ClientToScreen(rcClient);

	CDC dcBkgnd;
	dcBkgnd.CreateCompatibleDC(pDC);

	CBitmap bmpBkgnd;
	bmpBkgnd.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height());

	CBitmap * pOldBmpBkgnd = NULL;
	pOldBmpBkgnd = dcBkgnd.SelectObject(&bmpBkgnd);

	CDC dcImage;
	dcImage.CreateCompatibleDC(pDC);

	STATUS st;

	if (!IsWindowEnabled())
	{
		st = disable;
	}
	else if (m_bSelect)
	{
		st = select;
	}
	else if (CursorInWindow())
	{
		st = focus;
	}
	else
	{
		st = normal;
	}

	CBitmap* pOldBgBitmapImage = dcImage.SelectObject(&m_bmpBkgnd);

	//dcBkgnd.TransparentBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcImage, 0, 0, rcClient.Width(), rcClient.Height(), m_crComboBkgnd);
	dcBkgnd.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcImage, rcClient.Width()*st, 0, SRCCOPY);
	dcImage.SelectObject(pOldBgBitmapImage);

//	pDC->BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcBkgnd, 0, 0, SRCCOPY);
	pDC->FillSolidRect(rcClient, m_crComboBkgnd);
	pDC->TransparentBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcBkgnd, 0, 0, rcClient.Width(), rcClient.Height(), RGB(255,0,255));
	dcBkgnd.SelectObject(pOldBmpBkgnd);

	if (bAlloc)
	{
		ReleaseDC(pDC);
	}
}

void CEXDropdownComboBox::DrawText(CDC * pDC, int nIndex, CRect * prcText)
{
	CString strItem;
	GetLBText(nIndex, strItem);

	if (!strItem.IsEmpty())
	{
		if (strItem.GetLength())
		{
			CFont * pOldFont = pDC->SelectObject(GetFont());
			int nBkMode = pDC->SetBkMode(TRANSPARENT);
			CSize szFont = pDC->GetTextExtent(strItem);
			pDC->DrawText(strItem, prcText, DT_SINGLELINE|DT_VCENTER);
			pDC->SetBkMode(nBkMode);
			pDC->SelectObject(pOldFont);
		}
	}
}

void CEXDropdownComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
{ 
	int nWidth = lpMIS->itemWidth;
	int nHeight = lpMIS->itemHeight;
}

void CEXDropdownComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
  ASSERT(lpDrawItemStruct->CtlType == ODT_COMBOBOX);

  CDC dc;
  dc.Attach(lpDrawItemStruct->hDC);

  DWORD dwTickCount = GetTickCount();

  COLORREF crOldTextColor = dc.GetTextColor();
  COLORREF crOldBkColor = dc.GetBkColor();

  if (lpDrawItemStruct->itemAction & ODA_DRAWENTIRE &&
    lpDrawItemStruct->itemState & ODS_COMBOBOXEDIT)
  {
    DrawFrame(NULL);
  }

  if (!(lpDrawItemStruct->itemState & ODS_COMBOBOXEDIT))
  {
    if ((lpDrawItemStruct->itemAction | ODA_SELECT) &&
      (lpDrawItemStruct->itemState  & ODS_SELECTED))
    {
      dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
      dc.SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
      dc.FillSolidRect(&lpDrawItemStruct->rcItem, m_crListFocus);
      dc.DrawFocusRect(&lpDrawItemStruct->rcItem);
    }
    else
    {
      dc.FillSolidRect(&lpDrawItemStruct->rcItem, m_crListNormal);
    }

    if (lpDrawItemStruct->itemID != -1)
    {
      CRect rcText(lpDrawItemStruct->rcItem);
      rcText.DeflateRect(5, 1, 1, 5);
      DrawText(&dc, lpDrawItemStruct->itemID, &rcText);
    }
  }

  dc.SetTextColor(crOldTextColor);
  dc.SetBkColor(crOldBkColor);

  dc.Detach();
}

void CEXDropdownComboBox::PreSubclassWindow()
{
	ModifyStyle(0, WS_CLIPCHILDREN);

	CComboBox::PreSubclassWindow();

	ASSERT(GetStyle() & CBS_DROPDOWN);
	ASSERT(GetStyle() & CBS_OWNERDRAWVARIABLE);
	ASSERT(GetStyle() & CBS_HASSTRINGS);

	m_pChildEdit = (CEdit*)FindWindowEx(GetSafeHwnd(), NULL, L"Edit", NULL);

	if (m_pChildEdit)//!IsWindow(m_edText.GetSafeHwnd()))
	{
		CRect rcEdit;
		m_pChildEdit->GetWindowRect(rcEdit);
		ScreenToClient(rcEdit);

		DWORD dwEditStyle = m_pChildEdit->GetStyle()|ES_MULTILINE|ES_AUTOHSCROLL;

		m_pChildEdit->ShowWindow(SW_HIDE);

		m_edText.Create(dwEditStyle, rcEdit, this, -1);
	}

	RecalcDropWidth();
}

BOOL CEXDropdownComboBox::SetComboBgBitmaps(UINT nBkgndID, UINT nBtnID, 
                                            int nCount, COLORREF crBkgnd, 
                                            int nTopHeight/* = 0*/, 
                                            int nBottomHeight/* = 0*/, 
                                            int nLeftWidth/* = 0*/, 
                                            int nRightWidth/* = 20*/)
{
	m_nComboTopHeight = nTopHeight;
	m_nComboBottomHeight = nBottomHeight;
	m_nComboLeftWidth = nLeftWidth;
	m_nComboRightWidth = nRightWidth;

	m_nBtnID = nBtnID;
	m_nComboBkgndID = nBkgndID;
	m_nComboNumOfBgPics  = nCount;  

	m_crComboBkgnd = crBkgnd;

	CBitmap bmpTemp;
	if( !bmpTemp.LoadBitmap(m_nComboBkgndID) )
		return FALSE;

	CBitmap bmpBtn;
	if( !bmpBtn.LoadBitmap(m_nBtnID) )
		return FALSE;

	m_bmpBkgnd.DeleteObject();

	if( !InitBgBitmap( bmpTemp, bmpBtn, normal, m_nComboNumOfBgPics) ) 
		return FALSE;

	if( !InitBgBitmap( bmpTemp, bmpBtn, focus, m_nComboNumOfBgPics) )
		return FALSE;

	if( !InitBgBitmap( bmpTemp, bmpBtn, select, m_nComboNumOfBgPics) )
		return FALSE;

	if( !InitBgBitmap( bmpTemp, bmpBtn, disable, m_nComboNumOfBgPics) )
		return FALSE;
  
  m_bSetComboBg = TRUE;

	return TRUE;
}

BOOL CEXDropdownComboBox::SetEditBgBitmaps(UINT nBkgndID, int nCount, 
                                           COLORREF crBkgnd, 
                                           int nTopHeight/* = 0*/, 
                                           int nBottomHeight/* = 0*/, 
                                           int nLeftWidth/* = 0*/, 
                                           int nRightWidth/* = 0*/)
{
	ASSERT(IsWindow(m_edText.GetSafeHwnd()));

	return m_edText.SetBgBitmaps(nBkgndID, nCount, RGB(109, 111, 134), nTopHeight, 
                              nBottomHeight, nLeftWidth, nRightWidth);
}

BOOL CEXDropdownComboBox::InitBgBitmap(CBitmap & src, CBitmap & bmpBtn, 
                                       int index, int count)
{
	CDC * pDC = GetDC();

	CDC memDC; 
	memDC.CreateCompatibleDC(pDC);

	CDC srcDC;
	srcDC.CreateCompatibleDC(pDC);

	CBitmap* pOldBitmap1;
	pOldBitmap1 = srcDC.SelectObject(&src);

	BITMAP bmpinfo;
	src.GetBitmap(&bmpinfo);
	int bmpWidth = bmpinfo.bmWidth / count;
	int bmpHeight = bmpinfo.bmHeight;
	int orix = bmpWidth * (index < count ? index : 0);

	CRect rc;
	//	GetClientRect(rc);
	GetWindowRect(rc);
	rc.OffsetRect(-rc.left, -rc.top);

	CBitmap dist;
	dist.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height());

	CBitmap* pOldBitmap2 = memDC.SelectObject(&dist);

	memDC.FillSolidRect(rc, m_crComboBkgnd);

//   if(!m_nComboTopHeight && !m_nComboBottomHeight && !m_nComboLeftWidth)
//     memDC.StretchBlt(0,0,rc.Width(),rc.Height(),
//     &srcDC, orix, 0, bmpWidth, bmpHeight, SRCCOPY);

//   else
//  {
	// entireimage
	if (!memDC.TransparentBlt(m_nComboLeftWidth,
		m_nComboTopHeight,
		rc.Width()  - ( m_nComboLeftWidth + m_nComboRightWidth ) ,
		rc.Height() -  ( m_nComboTopHeight + m_nComboBottomHeight) ,
		&srcDC,
		orix + m_nComboLeftWidth,
		m_nComboTopHeight,
		bmpWidth - ( m_nComboLeftWidth + m_nComboRightWidth ) ,
		bmpHeight - ( m_nComboTopHeight + m_nComboBottomHeight ) , m_crComboBkgnd))
		return FALSE;

	// topbar
	if (!memDC.TransparentBlt(m_nComboLeftWidth,0, rc.Width() - (m_nComboLeftWidth + m_nComboRightWidth), m_nComboTopHeight,
		&srcDC,orix + m_nComboLeftWidth, 0, bmpWidth - ( m_nComboLeftWidth + m_nComboRightWidth) , m_nComboTopHeight, m_crComboBkgnd))
		return FALSE;

	// bottombar
	if (!memDC.TransparentBlt(m_nComboLeftWidth, rc.bottom - m_nComboBottomHeight, rc.Width() - ( m_nComboLeftWidth + m_nComboRightWidth), m_nComboBottomHeight,
		&srcDC,orix + m_nComboLeftWidth,bmpHeight - m_nComboBottomHeight,bmpWidth - ( m_nComboLeftWidth + m_nComboRightWidth) , m_nComboBottomHeight, m_crComboBkgnd ))
		return FALSE;

	// sidebar
	if (!memDC.TransparentBlt(0,m_nComboTopHeight,m_nComboLeftWidth,rc.bottom - m_nComboTopHeight - m_nComboBottomHeight ,
		&srcDC, orix,m_nComboTopHeight, m_nComboLeftWidth, bmpHeight - ( m_nComboTopHeight + m_nComboBottomHeight ) , m_crComboBkgnd))
		return FALSE;

	if (!memDC.TransparentBlt(rc.right - m_nComboRightWidth ,m_nComboTopHeight,m_nComboRightWidth,rc.bottom - m_nComboTopHeight - m_nComboBottomHeight ,
		&srcDC, orix +  bmpWidth - m_nComboRightWidth,m_nComboTopHeight, m_nComboRightWidth, bmpHeight - m_nComboTopHeight - m_nComboBottomHeight , m_crComboBkgnd))
		return FALSE;

	// lefttop,leftbottom,righttop,rightbottom
	if( !memDC.BitBlt(0, 0, m_nComboLeftWidth, m_nComboTopHeight, &srcDC, orix, 0, SRCCOPY) )
		return FALSE;

	if( !memDC.BitBlt(0,rc.bottom - m_nComboBottomHeight, m_nComboLeftWidth, m_nComboBottomHeight, 
		&srcDC,orix,bmpHeight - m_nComboBottomHeight, SRCCOPY) )
		return FALSE;

	if( !memDC.BitBlt(rc.right - m_nComboRightWidth, 0, m_nComboRightWidth, m_nComboTopHeight, 
		&srcDC,orix + bmpWidth - m_nComboRightWidth, 0, SRCCOPY) )
		return FALSE;

	if( !memDC.BitBlt(rc.right - m_nComboRightWidth, rc.bottom - m_nComboBottomHeight,m_nComboRightWidth, m_nComboBottomHeight,
		&srcDC,orix + bmpWidth - m_nComboRightWidth, bmpHeight - m_nComboBottomHeight, SRCCOPY) )
		return FALSE;
 //}
	bmpBtn.GetBitmap(&bmpinfo);
	int bmpBtnWidth = bmpinfo.bmWidth / count;
	int bmpBtnHeight = bmpinfo.bmHeight;
	int Btnorix = bmpBtnWidth * (index < count ? index : 0);

	CDC bmpBtnDC;
	bmpBtnDC.CreateCompatibleDC(pDC);

	CBitmap * pOldBmpBtn = NULL;
	pOldBmpBtn = bmpBtnDC.SelectObject(&bmpBtn);

	int nRightWidth = m_nComboRightWidth-1;

	int nOffX = rc.Width()-m_nComboRightWidth+((nRightWidth-bmpBtnWidth)/2);
	int nOffY = (rc.Height()-bmpBtnHeight)/2+1;

	memDC.TransparentBlt(nOffX, nOffY, bmpBtnWidth, bmpBtnHeight, &bmpBtnDC, 
                        Btnorix, 0, bmpBtnWidth, bmpBtnHeight, RGB(255,0,255));

	if (!m_bmpBkgnd.GetSafeHandle())
		m_bmpBkgnd.CreateCompatibleBitmap(pDC, rc.Width()*count, rc.Height());

	CDC dcBkgnd;
	dcBkgnd.CreateCompatibleDC(pDC);

	CBitmap * pOldBitmap3 = dcBkgnd.SelectObject(&m_bmpBkgnd);

	dcBkgnd.BitBlt(rc.Width()*index, 0, rc.Width(), rc.Height(), 
                &memDC, 0, 0, SRCCOPY);
	
	bmpBtnDC.SelectObject(pOldBmpBtn);
	srcDC.SelectObject(pOldBitmap1);
	memDC.SelectObject(pOldBitmap2);
	dcBkgnd.SelectObject(pOldBitmap3);

	ReleaseDC(pDC);
	ReleaseDC(&srcDC);
	ReleaseDC(&memDC);
	ReleaseDC(&dcBkgnd);

	return TRUE;
}

void CEXDropdownComboBox::OnSize(UINT nType, int cx, int cy)
{
	CComboBox::OnSize(nType, cx, cy);

	if (IsWindow(GetSafeHwnd()) && m_bSetComboBg)
	{
		SetComboBgBitmaps(m_nComboBkgndID, m_nBtnID, m_nComboNumOfBgPics, 
                      m_crComboBkgnd, m_nComboTopHeight, m_nComboBottomHeight, 
                      m_nComboLeftWidth, m_nComboRightWidth);
	}
  if (m_pChildEdit)
  {
    CRect rcEdit;
    m_pChildEdit->GetWindowRect(rcEdit);
    ScreenToClient(rcEdit);
    rcEdit.bottom += 1;
    m_edText.MoveWindow(rcEdit);
  }
}

void CEXDropdownComboBox::SetFont(CFont* pFont, BOOL bRedraw /*= TRUE*/)
{
	ASSERT(IsWindow(m_edText.GetSafeHwnd()));

	CComboBox::SetFont(pFont, bRedraw);
	m_edText.SetFont(pFont, bRedraw);
	m_edText.ModifyRect();

	RecalcDropWidth();
}

void CEXDropdownComboBox::OnCbnCloseup()
{
 	m_bSelect = FALSE;
	DrawFrame(NULL);

	int nIndex = GetCurSel();

	if (nIndex != CB_ERR)
	{
		CString strTxt;
		GetLBText(nIndex, strTxt);

		m_edText.SetWindowText(strTxt);
	}
}

void CEXDropdownComboBox::OnCbnDropdown()
{
	RecalcDropWidth();
 	m_bSelect = TRUE;
 	DrawFrame(NULL);
}

void CEXDropdownComboBox::RecalcDropWidth()
{
	// Reset the dropped width
	int nNumEntries = GetCount();
	int nWidth = 0;
	CString str;

	CClientDC dc(this);
	int nSave = dc.SaveDC();
	dc.SelectObject(GetFont());

	int nScrollWidth = 10;
	if (GetStyle() & WS_VSCROLL)
		nScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL);

	for (int i = 0; i < nNumEntries; i++)
	{
		GetLBText(i, str);
		int nLength = dc.GetTextExtent(str).cx + 4 + nScrollWidth;
		nWidth = max(nWidth, nLength);

		SetItemHeight(i, dc.GetTextExtent(str).cy+8);
	}

	// Add margin space to the calculations
	nWidth += dc.GetTextExtent(_T("0")).cx;

	int nHeight = dc.GetTextExtent(_T("0")).cy+4;
	SetItemHeight(-1, nHeight/* > 23 ? nHeight : 23*/);

	dc.RestoreDC(nSave);
	SetDroppedWidth(nWidth);
}

BOOL CEXDropdownComboBox::OnEraseBkgnd(CDC* pDC)
{
  if(!m_bSetComboBg)
    return CComboBox::OnEraseBkgnd(pDC);
  else
  {
    DrawFrame(NULL);
    return FALSE;
  }
}

void CEXDropdownComboBox::OnNcPaint()
{
  if(!m_bSetComboBg)
    CComboBox::OnNcPaint();
  else
    DrawFrame(NULL);
}

void CEXDropdownComboBox::OnPaint()
{
  if(!m_bSetComboBg)
    CComboBox::OnPaint();
  else
  {
    CPaintDC dc(this); // device context for painting
    DrawFrame(&dc);
  }
}

void CEXDropdownComboBox::OnTimer(UINT_PTR nIDEvent)
{
	CComboBox::OnTimer(nIDEvent);
}

void CEXDropdownComboBox::OnDestroy()
{
	CComboBox::OnDestroy();
}

int CEXDropdownComboBox::SetCurSel(int nSelect)
{
	int nRet = CComboBox::SetCurSel(nSelect);

  CString strTxt;
  GetWindowText(strTxt);
  m_edText.SetWindowText(strTxt);

	return nRet;
}

void CEXDropdownComboBox::ResetContent()
{
	CComboBox::ResetContent();
	m_edText.SetWindowText(L"");
}

void CEXDropdownComboBox::SetWindowText(LPCTSTR lpszString)
{
	CComboBox::SetWindowText(lpszString);
	m_edText.SetWindowText(lpszString);
}

LRESULT CEXDropdownComboBox::OnDefEnchange(WPARAM w, LPARAM l)
{
	CString strTxt;
	m_edText.GetWindowText(strTxt);
	m_pChildEdit->SetWindowText(strTxt);

	return 0;
}

int CEXDropdownComboBox::SelectString(int nStartAfter, LPCTSTR lpszString)
{
	int nRet = CComboBox::SelectString(nStartAfter, lpszString);

	if (nRet != CB_ERR)
	{
		CString strTxt;
		GetLBText(nRet, strTxt);
		m_edText.SetWindowText(strTxt);
	}

	return nRet;
}

void CEXDropdownComboBox::SetListColor(COLORREF crNoral, COLORREF crFocus)
{
	m_crListNormal = crNoral;
	m_crListFocus = crFocus;

	Invalidate(FALSE);
}

void CEXDropdownComboBox::OnWindowPosChanging(WINDOWPOS* lpwndpos)
{
	CComboBox::OnWindowPosChanging(lpwndpos);
}

void CEXDropdownComboBox::OnWindowPosChanged(WINDOWPOS* lpwndpos)
{
	CComboBox::OnWindowPosChanged(lpwndpos);
}
